import { calendarWrap, calendarValueWrap, format, formatDateObj } from '../../utils'

/**
 * 日历组件
 * @param {string|Element} 容器
 * @param {Object} options
 * @type {Calendar}
 */
export const Calendar = (function(win, doc) {
    class Calendar {
        constructor(wrap, options) {
            if (!wrap) {
                throw new Error('The container cannot be empty！')
            }
            this.wrap = typeof wrap  === 'string' ? doc.querySelector(wrap) : wrap
            this.init(options)
        }
        _isInit = false;
        curYear = null;
        curMonth = null;
        curDate = null;

        /**
         * 初始化
         * @param options
         */
        init(options) {
            this.options = options
            this.valueChange(options.value)
            this.bindEvent() // 绑定事件
            this._isInit = true
        }

        /**
         * 值切换
         * @param {number} newVal
         */
        valueChange(newVal) {
            this.setValue(newVal) // 设置存储值
            this.renderValue() // 渲染值
            this.renderContent() // 渲染表格内容
            this._isInit && this.runCallback() // 执行回调函数
        }

        /**
         * 设置值
         * @param {number} val 时间戳
         */
        setValue(val) {
            let defaultVal = val ? new Date(val) : new Date()
            defaultVal = new Date(defaultVal.setHours(0, 0, 0))
            this.selected = defaultVal.getTime()
            this.curYear = defaultVal.getFullYear()
            this.curMonth = defaultVal.getMonth() + 1
            this.curDate = defaultVal.getDate()
        }

        /**
         * 渲染值
         */
        renderValue() {
            const val = this.selected
            this.wrap.querySelector('.calendar-header__value').innerHTML = format(val)
        }

        /**
         * 绑定事件
         */
        bindEvent() {
            const { wrap } = this
            const tableBody = wrap.querySelector('.calendar-body')
            const header = wrap.querySelector('.calendar-header')
            tableBody.addEventListener('click', this.handlerClick.bind(this), false)
            // 头部上月、下月事件
            header.addEventListener('click', this.handlerPrevNextMonth.bind(this), false)
            // 头部上一年、一下年
            header.addEventListener('click', this.handlerPrvNextYear.bind(this), false)
        }

        /**
         * 上月、下一月
         */
        handlerPrevNextMonth(e) {
            const target = e.target
            const type = target.getAttribute('data-type')
            if (type && ["prevMonth", 'nextMonth'].includes(type)) {
                const { curMonth } = this
                const newMonth = type === 'prevMonth' ? curMonth-1 : curMonth+1
                const newDate = new Date(this.curYear, newMonth - 1, 1, 0, 0, 0, 0)
                this.valueChange(newDate.getTime())
            }
        }

        /**
         * 上一年、下一年
         * @param e
         */
        handlerPrvNextYear(e) {
            const target = e.target
            const type = target.getAttribute('data-type')
            if (type && ["prevYear", 'nextYear'].includes(type)) {
                const { curYear } = this
                const newYear = type === 'prevYear' ? curYear-1 : curYear+1
                const newDate = new Date(newYear, this.curMonth - 1, 1, 0, 0, 0, 0)
                this.valueChange(newDate.getTime())
            }
        }

        /**
         * click事件
         * @param e
         */
        handlerClick(e) {
            const target = e.target
            if (['TD', 'SPAN'].includes(target.nodeName)) {
                this.valueChange(+target.getAttribute('data-value'))
            }
        }

        /**
         * 获取class名称
         * @param type
         * @return {string|string}
         */
        getClassName(type, item) {
            const { selected } = this
            const className = []

            // 当月
            if (type === 'current') {
                className.push('available')
            } else {
                // 上月或者下月
                if (type === 'last') {
                    className.push('prev-month')
                } else {
                    className.push('next-month')
                }
            }

            // 是否选中
            if (item.date === selected) {
                className.push('active')
            }
            return className.join(' ')

        }

        /**
         * 渲染内容
         */
        renderContent() {
            const { curYear: year, curMonth: month } = this
            const { last, current, next } = calendarWrap(year, month)
            const valueWrap = calendarValueWrap(year, month) // 值
            const dayList = [...last, ...current, ...next]
            const dateValueList = [...valueWrap.last, ...valueWrap.current, ...valueWrap.next]
            let domStr = `<table class="calendar-table" border="0" cellspacing="0" cellpadding="0">`
            let header = `
                <thead class="date-table__header">
                    <tr class="date-table__row">
                        <td>一</td>
                        <td>二</td>
                        <td>三</td>
                        <td>四</td>
                        <td>五</td>
                        <td>六</td>
                        <td>日</td>
                    </tr>
                </thead>
            `;
            domStr += header
            let body = `<tbody class="date-table__body">`
            for (let i = 0, len = dayList.length; i < len; i++) {
                const day = dayList[i]
                const val = dateValueList[i]
                const itemClassName = this.getClassName(val.type, val)
                if (i === 0 || i % 7 === 0) {
                    body += i === 0 ? '<tr class="date-table__row">' : '</tr><tr class="date-table__row">'
                }
                body += i === len - 1 ? `<td class="${itemClassName}" data-value="${val.date}"><span class="text" data-value="${val.date}">${day}</span></td></tr>` : `<td class="${itemClassName}" data-value="${val.date}"><span class="text" data-value="${val.date}">${day}</span></td>`
            }
            body += '</tbody>'
            domStr += `${body}</table>`
            this.wrap.querySelector('.calendar-body').innerHTML = domStr
        }

        /**
         * 执行回调函数
         */
        runCallback() {
            const { onChange } = this.options
            if (typeof onChange === 'function') {
                onChange(this.selected, formatDateObj(this.selected))
            }
        }
    }
    return Calendar
})(window, document);
